﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using dbPoll_Application.Models;
using dbPoll_Application.ViewModels;
using NHibernate;
using dbPoll_Application.Helpers;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Collections;

namespace dbPoll_Application.Controllers
{
    public class PollController : Controller
    {
        private double brisbaneLatitude = -27.4709180316061;
        private double brisbaneLongitude = 153.023501693512;

        [Authorize]
        public ActionResult Index()
        {
            var user = UserRepository.GetUserByUsername(User.Identity.Name);
            var allPolls = new List<Poll>();
            allPolls.AddRange(user.ManagedPolls);
            allPolls.AddRange(user.CreatedPolls);
            allPolls.AddRange(PollRepository.GetPollsMasteredBy(user));
            return View(allPolls.Distinct<Poll>().OrderByDescending(p => p.pollID).ToList<Poll>());           
        }
        
        [Authorize]
        public int hasParticipant(Boolean hasParticipant, int pollID, Poll p)
        {
            if (pollID == -1) pollID = AddPoll(p);
            Poll poll = PollRepository.GetPollByID(pollID);
            poll.hasParticipantList = hasParticipant;
            PollRepository.UpdatePoll(poll);

            return pollID;
        }

        [Authorize]
        public ActionResult ListofParticipants(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            return View(new ParticipantFieldViewModel(poll));
        }

        [Authorize]
        public ViewResult ApplyParticipantListTemplate(int pollID, int templateID, int lastTemplateID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var model = new ParticipantFieldViewModel(poll);
            
            model.selectedTemplateID = templateID;

            if (templateID != -1)
            {
                var fields = FieldsTemplateRepository.GetTemplateByTemplateID(templateID).fields;
                var participantFields = new List<ParticipantField>();
                foreach (var field in fields)
                {
                    participantFields.Add(new ParticipantField(field.name));
                }
                IList<ParticipantField> pl = model.poll.participantFields.ToList();
                foreach (ParticipantField p in pl)
                {
                    model.poll.participantFields.Remove(p);
                    ParticipantRepository.DeleteFields(p);
                }
                foreach (ParticipantField p in participantFields) model.poll.participantFields.Add(p);
                PollRepository.UpdatePoll(poll);
                model = new ParticipantFieldViewModel(poll);
            }
            else
            {
                var fields = FieldsTemplateRepository.GetTemplateByTemplateID(lastTemplateID).fields;
                IList<ParticipantField> pfields = new List<ParticipantField>();
                foreach (var field in fields)
                {
                    foreach (var participantField in model.poll.participantFields)
                    {
                        if (field.name == participantField.name)
                        {
                            pfields.Add(participantField);
                        }
                    }
                }
                foreach (var pfield in pfields)
                {
                    model.poll.participantFields.Remove(pfield);
                }
                PollRepository.UpdatePoll(poll);
                model = new ParticipantFieldViewModel(poll);
            }
            if (poll.isGroup) return View("Group", model);
            return View("Individual", model);
        }

        [Authorize]
        public ActionResult Questions(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            if (poll.participants.Where(m => m.isTestParticipant).Count() > 0)
            {
                RemoveTestParticipants(pollID);
            }
            if (poll.isTestPoll)
            {
                poll = poll.linkedPoll;
            }
            var user = UserRepository.GetUserByUsername(User.Identity.Name);
            var users = UserRepository.GetCreatorsOfPoll(poll);
            ViewData["pollCreators"] = users.ToList<User>();
            ViewData["pollRoles"] = SecurityHelper.GetRolesForPole(user, poll);

            return View(poll);
        }

        [Authorize]
        public ActionResult CreatePoll()
        {
            var poll = new Poll(brisbaneLatitude, brisbaneLongitude);
            ViewData["pollCreators"] = new List<User>();
            var pollRoles = new HashSet<Role>();
            pollRoles.Add(new Role("Poll Administrator"));
            ViewData["pollRoles"] = pollRoles;

            return View("Questions", poll);
        }

        [Authorize]
        public int AddPoll(Poll p)
        {
            var poll = new Poll(brisbaneLatitude, brisbaneLongitude);
            var user = UserRepository.GetUserByUsername(User.Identity.Name);
            poll.name = p.name;
            poll.receiverChannel = p.receiverChannel;
            user.ManagedPolls.Add(poll);
            UserRepository.Update(user);

            return poll.pollID;
        }

        [Authorize]
        public int AddPollGetTest(Poll p)
        { 
            int pollID = AddPoll(p);
            Poll poll = PollRepository.GetPollByID(pollID);
            return poll.linkedPoll.pollID;
        }

        [Authorize]
        public int GetTestPoll(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            return poll.linkedPoll.pollID;
        }

        [Authorize]
        public int UpdatePoll(Poll p)
        {
            var poll = PollRepository.GetPollByID(p.pollID);
            poll.name = p.name;
            poll.receiverChannel = p.receiverChannel;
            poll.genericUsers = p.genericUsers;
            PollRepository.UpdatePoll(poll);

            return poll.pollID;
        }

        [Authorize]
        public ActionResult Participants(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            return View(new ParticipantFieldViewModel(poll));
        }

        [Authorize]
        [HttpPost]
        public ActionResult Participants(int pollID,string type)
        {
            var poll = PollRepository.GetPollByID(pollID);
            if (type == "Group") poll.isGroup = true;
            else poll.isGroup = false;
            UpdatePoll(poll);
            return View(new ParticipantFieldViewModel(poll));
        }

        [Authorize]
        public ActionResult SelectPollCreator(int pollID)
        {
            var allPollCreators = UserRepository.GetUsersByRoleName("Poll Creator");
            var poll = PollRepository.GetPollByID(pollID);
            var currentPollCreators = UserRepository.GetCreatorsOfPoll(poll);
            var potentialPollCreators = allPollCreators.Except(currentPollCreators).ToList<User>();

            return View("SelectUser", new SelectUserViewModel(potentialPollCreators, new Role("Poll Creator"), pollID, poll.name));
        }

        [Authorize]
        public ActionResult SelectPollMaster(int pollID)
        {
            var allPollMasters = UserRepository.GetUsersByRoleName("Poll Master");
            var poll = PollRepository.GetPollByID(pollID);
            var currentPollMasters = poll.pollMasters;
            var potentialPollMasters = allPollMasters.Except(currentPollMasters).ToList<User>();

            return View("SelectUser", new SelectUserViewModel(potentialPollMasters, new Role("Poll Master"), pollID, poll.name));
        }

        [Authorize]
        public bool DeleteGroup(int groupID, int pollID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            using (ITransaction transaction = session.BeginTransaction())
            {
                ParticipantGroup group = ParticipantRepository.GetGroupByGroupID(groupID);
                foreach (Participant participant in PollRepository.GetPollByID(pollID).participants)
                    if (participant.group == group) participant.group = null;
                session.Delete(group);
                transaction.Commit();
                return transaction.WasCommitted;
            }
        }

        [Authorize]
        public Boolean AddPollCreator(int pollID, String UserName)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(UserName);
            user.CreatedPolls.Add(poll);
            bool success = UserRepository.Update(user);
            if (success) EmailAssignedUser(pollID, UserName, "Poll Master");
            return success;
        }

        [Authorize]
        public Boolean AddPollMaster(int pollID, String UserName)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(UserName);
            poll.pollMasters.Add(user);
            bool success = PollRepository.UpdatePoll(poll);
            if (success) EmailAssignedUser(pollID, UserName, "Poll Master");
            return success;
        }

        [Authorize(Roles = "Poll Administrator, Poll Creator")]
        public void EmailAssignedUser(int pollID, String UserName, String roleName)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(UserName);
            var message = Email.CreateAssignBody(user.UserName, poll.name, roleName);
            Email.SendPlainEmail("donotreplydbpoll@gmail.com", user.Email, "dbPoll message", message);
        }

        [Authorize]
        public Boolean RemovePollCreator(int pollID, String UserName)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(UserName);
            user.CreatedPolls.Remove(poll);

            return UserRepository.Update(user);
        }

        [Authorize]
        public Boolean RemovePollMaster(int pollID, String UserName)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(UserName);
            poll.pollMasters.Remove(user);

            return PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public int UpdatePollLocation(int pollID, double latitude, double longitude, Poll p)
        {
            if (pollID == -1) pollID = AddPoll(p);
            Poll poll = PollRepository.GetPollByID(pollID);
            poll.latitude = latitude;
            poll.longitude = longitude;
            PollRepository.UpdatePoll(poll);
            return pollID;
        }

        [Authorize]
        public Boolean UpdatePollSettings(Poll p)
        {
            var poll = PollRepository.GetPollByID(p.pollID);
            poll.pollClose = p.pollClose;
            poll.defaultCountdownTimer = p.defaultCountdownTimer;
            poll.defaultResponseCounter = p.defaultResponseCounter;
            poll.defaultCorrectAnswerIndicator = p.defaultCorrectAnswerIndicator;
            poll.defaultResponseGrid = p.defaultResponseGrid;
            poll.defaultFontType = p.defaultFontType;
            poll.defaultFontColour = p.defaultFontColour;
            poll.defaultFontSize = p.defaultFontSize;
            poll.defaultResultsChart = p.defaultResultsChart;

            return PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public Boolean UpdateCloseSettings(Poll p)
        {
            var poll = PollRepository.GetPollByID(p.pollID);
            poll.pollClose = p.pollClose;
            return PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public bool Delete(int participantID, int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            ISession session = NHibernateHelper.GetCurrentSession();
            poll.participants.Remove(ParticipantRepository.GetParticipantByParticipantID(participantID));
            PollRepository.UpdatePoll(poll);
            return ParticipantRepository.Delete(participantID);
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult SetSession(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            return View(poll);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public void SetSession(int pollID, double latitude, double longitude)
        {
            var poll = PollRepository.GetPollByID(pollID);
            PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public ActionResult Run(int pollID, String testPoll)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(User.Identity.Name);
            ViewData["pollRoles"] = SecurityHelper.GetRolesForPole(user, poll);
            ViewData["results"] = ReportRepository.GetAllQuestionResults(pollID);
            if (testPoll != null)
            {
                ViewData["testPoll"] = "true";
            }
            else
            {
                ViewData["testPoll"] = "false";
            }
            return View(poll);
        }

        [Authorize]
        public JsonResult GetLatestQuestionResults(int pollID)
        {
            return Json(ReportRepository.GetAllQuestionResults(pollID));
        }

        [Authorize]
        public ActionResult Test(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(User.Identity.Name);
            ViewData["pollRoles"] = SecurityHelper.GetRolesForPole(user, poll);
            return View(poll);
        }

        [Authorize]
        public ActionResult Reports(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            if (poll.participants.Where(m => m.isTestParticipant).Count() > 0)
            {
                RemoveTestParticipants(pollID);
            }
            IList<Question> questions = poll.questions;
            IDictionary<String, int> responses = new Dictionary<String, int>();

            var viewModel = new PollReportViewModel(pollID, poll.name);
            return View(viewModel);    
        }

        [Authorize]
        public ActionResult SessionParticipationTextual(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<Participant> participants = poll.participants;
            var viewModel = new PollReportViewModel(pollID, poll.name, participants);
            return View(viewModel);
        }

        [Authorize]
        public ActionResult SessionParticipationGraphical(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<Participant> participants = poll.participants;

            var viewModel = new PollReportViewModel(pollID, poll.name, participants);
            return View(viewModel);
        }
        [Authorize]
        public IDictionary<String, int> QuestionResult(Question question)
        {
            // Create a dictionary to store that question's responses
            IDictionary<String, int> responses = new Dictionary<String, int>();

            if (question.type == QuestionType.Numeric)
            {
                // If a numeric question
                NumericQuestion numericQuestion = QuestionRepository.GetQuestionByID<NumericQuestion>(question.questionID);

                int numCorrect = 0;
                int numIncorrect = 0;

                foreach (var response in numericQuestion.responses)
                {
                    // Check if the answer is correct
                    if ((Convert.ToInt32(response.response) < numericQuestion.lessThan) &&
                        (Convert.ToInt32(response.response) > numericQuestion.greaterThan))
                    {
                        numCorrect += response.participant.votingWeight;
                    }
                    else
                    {
                        numIncorrect += response.participant.votingWeight;
                    }

                }
                if (numericQuestion.lessThan-numericQuestion.greaterThan==2)
                    responses.Add("Correct [" + (numericQuestion.greaterThan+1) + "]", numCorrect);
                else responses.Add("Correct [" + numericQuestion.greaterThan.ToString() +
                        " - " + numericQuestion.lessThan.ToString() + "]", numCorrect);
                responses.Add("Incorrect", numIncorrect);

            }
            else if (question.type == QuestionType.Alphanumeric)
            {
                // If an alphanumeric question
                AlphanumericQuestion alphaQuestion = QuestionRepository.GetQuestionByID<AlphanumericQuestion>(question.questionID);

                //  Get correct responses
                int numCorrect = 0;
                int numIncorrect = 0;
                int total = 0;

                foreach (var response in alphaQuestion.responses)
                {
                    foreach (var answer in alphaQuestion.answers)
                    {
                        if (response.response.Equals(answer.answer))
                        {
                            numCorrect += response.participant.votingWeight;
                        }
                    }
                    total += response.participant.votingWeight;
                }

                // Build a string of correct answers
                String correctAnswers = "";
                foreach (var answer in alphaQuestion.answers)
                {
                    if (correctAnswers != "")
                    {
                        correctAnswers += ", ";
                    }
                    correctAnswers += answer.answer;
                }

                responses.Add("Correct [" + correctAnswers + "]", numCorrect);
                numIncorrect = total - numCorrect;
                responses.Add("Incorrect", numIncorrect);
            }
            else if (question.type == QuestionType.Ranking)
            {
                RankingQuestion rankingQuestion = QuestionRepository.GetQuestionByID<RankingQuestion>(question.questionID);

                foreach (var option in rankingQuestion.options)
                {
                    int a = (from o in option.responses 
                             select o.participant.votingWeight*rankingQuestion.rankValues.ElementAt(o.rank-1).value).Sum();
                    responses.Add(option.answer, a);
                }
            }
            else
            {
                // IF MCQ
                MultipleChoiceQuestion multipleQuestion = QuestionRepository.GetQuestionByID<MultipleChoiceQuestion>(question.questionID);

                foreach (var option in multipleQuestion.options)
                {
                    int a = (from o in option.responses select o.participant.votingWeight).Sum();
                    responses.Add(option.answer, a);
                }
            }
            return responses;
        }

        [Authorize]
        public PollReportViewModel QuestionViewModel(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<Question> questions = poll.questions;

            IDictionary<Question, IDictionary<String, int>> questionResponses = new Dictionary<Question, IDictionary<String, int>>();

            // For each of the poll's questions
            foreach (Question question in questions)
            {
                
                // Add the question and its responses to the Dictionary
                questionResponses.Add(question, QuestionResult(question));
            }

            return new PollReportViewModel(pollID, poll.name, questions, questionResponses);
        }

        [Authorize]
        public IDictionary<Question, IDictionary<String, IDictionary<int, int>>> FilteredResponses(int pollID, IList<Entity> selectedEntities)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<Question> questions = poll.questions;

            IDictionary<Question, IDictionary<String, IDictionary<int, int>>> questionResponses = 
                new Dictionary<Question, IDictionary<String, IDictionary<int, int>>>();

            // For each of the poll's questions
            foreach (Question question in questions)
            {
                // Create a dictionary to store that question's responses
                IDictionary<String, IDictionary<int,int>> responses = new Dictionary<String, IDictionary<int,int>>();

                if (question.type == QuestionType.Numeric)
                {
                    // If a numeric question
                    NumericQuestion numericQuestion = QuestionRepository.GetQuestionByID<NumericQuestion>(question.questionID);

                    IDictionary<int, int> results = new Dictionary<int, int>();
                    IDictionary<int, int> iResults = new Dictionary<int, int>();

                    foreach (var entity in selectedEntities)
                    {

                        int numCorrect = 0;
                        int numIncorrect = 0;
                        results[entity.entityID] = 0;
                        iResults[entity.entityID] = 0;
                        foreach (var response in numericQuestion.responses)
                        {
                            if (response.participant.entity != null &&
                                    (entity.entityID == response.participant.entity.entityID ||
                                    EntityRepository.GetAllChildren(entity).Contains(response.participant.entity)))
                            {
                                if ((Convert.ToInt32(response.response) < numericQuestion.lessThan) &&
                                    (Convert.ToInt32(response.response) > numericQuestion.greaterThan))
                                {
                                    numCorrect+=response.participant.votingWeight;
                                }
                                else
                                {
                                    numIncorrect+=response.participant.votingWeight;
                                }
                                results[entity.entityID] = numCorrect;
                                iResults[entity.entityID] = numIncorrect;
                            }

                        }
                    }
                    if (numericQuestion.lessThan - numericQuestion.greaterThan == 2)
                        responses["Correct [" + numericQuestion.greaterThan.ToString() + "]"] = results;
                    else responses["Correct [" + numericQuestion.greaterThan.ToString() +
                            " - " + numericQuestion.lessThan.ToString() + "]"] = results;
                    
                    responses["Incorrect"] = iResults;
                }
                else if (question.type == QuestionType.Alphanumeric)
                {
                    // If an alphanumeric question
                    AlphanumericQuestion alphaQuestion = QuestionRepository.GetQuestionByID<AlphanumericQuestion>(question.questionID);

                    //  Get correct responses
                    
                    

                    IDictionary<int, int> results = new Dictionary<int, int>();
                    IDictionary<int, int> iResults = new Dictionary<int, int>();

                    foreach (var entity in selectedEntities)
                    {
                        int numCorrect = 0;
                        int numIncorrect = 0;
                        results[entity.entityID] = 0;
                        iResults[entity.entityID] = 0;
                        foreach (var response in alphaQuestion.responses)
                        {
                            foreach (var answer in alphaQuestion.answers)
                            {
                                if (response.participant.entity != null &&
                                    (entity.entityID == response.participant.entity.entityID ||
                                    EntityRepository.GetAllChildren(entity).Contains(response.participant.entity))) 
                                {
                                    if (response.response.Equals(answer.answer))
                                        numCorrect+=response.participant.votingWeight;
                                    else
                                        numIncorrect += response.participant.votingWeight; ;
                                }
                                results[entity.entityID] = numCorrect;
                                iResults[entity.entityID] = numIncorrect;
                            }
                        }
                        // Build a string of correct answers
                        String correctAnswers = "";
                        foreach (var answer in alphaQuestion.answers)
                        {
                            if (correctAnswers != "")
                            {
                                correctAnswers += ", ";
                            }
                            correctAnswers += answer.answer;
                        }

                        responses["Correct [" + correctAnswers + "]"] = results;
                        responses["Incorrect"] = iResults;
                    } 
                }
                else
                {
                    // IF MCQ
                    MultipleChoiceQuestion multipleQuestion = QuestionRepository.GetQuestionByID<MultipleChoiceQuestion>(question.questionID);

                    foreach (var option in multipleQuestion.options)
                    {
                        IDictionary<int,int> results = new Dictionary<int, int>();
                        foreach (var entity in selectedEntities)
                        {
                            results[entity.entityID] = 0;
                            int i = 0;
                            foreach (var response in option.responses) 
                            {
                                if (response.participant.entity != null && 
                                    (entity.entityID == response.participant.entity.entityID || 
                                    EntityRepository.GetAllChildren(entity).Contains(response.participant.entity)))
                                {
                                    i+=response.participant.votingWeight*Math.Abs(response.rank);
                                }
                                results[entity.entityID] = i;
                            }                                
                        }
                        responses.Add(option.answer, results);
                    }
                }

                // Add the question and its responses to the Dictionary
                questionResponses.Add(question, responses);
            }

            return questionResponses;
        }

        [Authorize]
        public ActionResult QuestionReportTextual(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            PollReportViewModel model = QuestionViewModel(pollID);
            CodeFile1 tryomg = new CodeFile1();
            PdfPTable table = tryomg.QuestionReport(Server.MapPath("/Resources"), model, null);
            IList<IElement> tab = new List<IElement>();
            tab.Add(table);
            tryomg.CreatePDF(tab, Server.MapPath("/Resources"), "Results by Question Report",poll.name);
            Entity root = null;
            foreach (Entity e in poll.entities)
            {
                if (e.parent == null)
                {
                    root = e;
                    break;
                }
            }
            model.root = root;
            return View(model);
        }

        [Authorize]
        public ActionResult ApplyQuestionReportGraphicalFilters(int pollID, int [] entityIDs)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            Entity root = null;
            var model = QuestionViewModel(pollID);
            foreach (Entity e in poll.entities)
            {
                if (e.parent == null)
                {
                    root = e;
                    break;
                }
            }
            model.root = root;
            if (entityIDs == null)
            {
                model.selectedEntities = new List<Entity>();
            }
            else
            {
                model.selectedEntities = EntityRepository.GetEntityByEntityIDs(entityIDs);
                model.filteredResponses = FilteredResponses(pollID, model.selectedEntities);
            }
            return View("ReportGraphical", model);
        }

        [Authorize]
        public ViewResult ApplyQuestionReportTextualFilters(int pollID, int[] entityIDs)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            PollReportViewModel model = QuestionViewModel(pollID);
            Entity root = null;
            foreach (Entity e in poll.entities)
            {
                if (e.parent == null)
                {
                    root = e;
                    break;
                }
            }
            model.root = root;
            if (entityIDs == null)
            {
                model.selectedEntities = new List<Entity>();
            }
            else
            {
                model.selectedEntities = EntityRepository.GetEntityByEntityIDs(entityIDs);
                model.filteredResponses = FilteredResponses(pollID, model.selectedEntities);
            }
            CodeFile1 tryomg = new CodeFile1();
            PdfPTable table = tryomg.QuestionReport(Server.MapPath("/Resources"), model, null);
            IList<IElement> tab = new List<IElement>();
            tab.Add(table);
            tryomg.CreatePDF(tab, Server.MapPath("/Resources"), "Results by Question Report", poll.name);
            return View("ReportTextual", model);
        }

        [Authorize]
        public ActionResult QuestionReportGraphical(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            Entity root = null;
            var model = QuestionViewModel(pollID);
            foreach (Entity e in poll.entities)
            {
                if (e.parent == null)
                {
                    root = e;
                    break;
                }
            }
            model.root = root;
            return View(model);
        }

        [Authorize]
        public ActionResult DemographicReportTextual(int pollID)
        {
            return QuestionReportTextual(pollID);
        }

        [Authorize]
        public ActionResult QuestionReportTextualPlain(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            return View(new PollReportViewModel(pollID,poll.name));
        }
        [Authorize]
        public RedirectToRouteResult SessionPdf(int pollID, String type) 
        {
            CodeFile1 tryomg = new CodeFile1();
            Poll poll = PollRepository.GetPollByID(pollID);
            PollReportViewModel viewModel = new PollReportViewModel(pollID, poll.name, poll.participants);
            PdfPTable table = tryomg.SessionParticipation(Server.MapPath("/Resources"),viewModel);
            IList<IElement> tab = new List<IElement>();
            tab.Add(table);
            tryomg.CreatePDF(tab, Server.MapPath("/Resources"), type, poll.name);
            return RedirectToAction("QuestionReportTextualPlain", new { pollID = pollID });
        }

        [Authorize]
        public ActionResult SystemReports()
        {
            var userList = UserRepository.GetUsers().Where(user => user.IsDeleted == false).ToList<User>();
            PollReportViewModel viewModel = new PollReportViewModel(userList);
            return View( viewModel);
        }

        [Authorize]
        public RedirectToRouteResult SessionGraphical(int pollID, String type, String urls, String way)
        {
            CodeFile1 pdf = new CodeFile1();
            IList<IElement> cell = new List<IElement>();
            cell.Add(new Paragraph(way, new Font(FontFactory.GetFont("Verdana", 14))) { Alignment = Element.ALIGN_CENTER });  
            if (urls.Contains(','))
            {
                String[] url = urls.Split(',');
                foreach (String ur in url) cell.Add(Image.GetInstance(new Uri("http:" + ur)));
                pdf.CreatePDF(cell, Server.MapPath("/Resources"), type, PollRepository.GetPollByID(pollID).name);
            }
            else
            {
                cell.Add(Image.GetInstance(new Uri("http:" + urls)));
                pdf.CreatePDF(cell, Server.MapPath("/Resources"), type, PollRepository.GetPollByID(pollID).name);
            }
            return RedirectToAction("QuestionReportTextualPlain", new { pollID = pollID });
        }
        [Authorize]
        [HttpPost]
        public ActionResult QuestionReportTextualPlain(int pollID, String urls,String name,bool? include, int? field, String items, String selectedEntities)
        {
            if (urls == null) return QuestionReportTextualPlain(pollID);
            
            Poll poll = PollRepository.GetPollByID(pollID);
            CodeFile1 tryomg = new CodeFile1();
            PollReportViewModel model = QuestionViewModel(pollID);
            model.include = include.GetValueOrDefault(false);
            if (!String.IsNullOrEmpty(selectedEntities))
            {
                int[] sEntities = commaStringToArray(selectedEntities);
                model.selectedEntities = EntityRepository.GetEntityByEntityIDs(sEntities);
            }
            if (field!=null) model.field = ParticipantRepository.GetParticipantFieldByID(field.Value);
            if (items != null) model.tick = items.Split('.');
            PdfPTable table = tryomg.GraphicalReport(Server.MapPath("/Resources"), poll, urls, model,null);
            IList<IElement> stuff = new List<IElement>();
            stuff.Add(table);
            tryomg.CreatePDF(stuff, Server.MapPath("/Resources"), name,poll.name);
            return View(new PollReportViewModel(pollID, poll.name));
        }

         private int[] commaStringToArray(string strComma)
         {
             string [] strArray;

             strArray = strComma.Split(new char[] {','});
             int [] intArray = new int [strArray.Length];

             for (int i = 0; i < strArray.Length; i++)
                intArray[i] = int.Parse(strArray[i]);

             return intArray;
         }

        [Authorize]
        public String demographicfield(int fieldID,int pollID,String [] items)
        {
            String result = "";
            Poll poll = PollRepository.GetPollByID(pollID);
            List<string> values = new List<string>();
            IList<ParticipantFieldValue> valued = ParticipantRepository.GetParticipantFieldByID(fieldID).fieldValues.Where(valu => (!valu.value.Equals(""))).ToList();
            if (poll.isGroup) valued = valued.Where(v => v.groupd != null).ToList();
            else valued = valued.Where(v => v.participant != null).ToList();
            values = (from v in valued select v.value).Distinct().ToList();
            bool num = true;
            int number;
            if (values.Any(v => (!int.TryParse(v, out number)))) num = false;
            if (num == false)
            {
                values.Sort((x, y) => string.Compare(x, y));
                foreach (String value in values)
                {
                    if (items != null && items.Contains(value))
                        result = result + "<label><input type=\"checkbox\" name=\"items\" checked=\"yes\" value=\"" + value + "\"/>" + value + "</label><br />";
                    else result = result + "<label><input type=\"checkbox\" name=\"items\" value=\"" + value + "\"/>" + value + "</label><br />";
                }
            }
            else
            {
                List<int> intvalues = values.ConvertAll<int>(delegate(String i) { return int.Parse(i); });
                intvalues.Sort();
                foreach (int value in intvalues)
                {
                    if (items != null && items.Contains(value.ToString()))
                        result = result + "<label><input type=\"checkbox\" name=\"items\" checked=\"yes\" value=\"" + value + "\"/>" + value + "</label><br />";
                    else result = result + "<label><input type=\"checkbox\" name=\"items\" value=\"" + value + "\"/>" + value + "</label><br />";
                }
            }
            return result;
        }
        [Authorize]
        public PollReportViewModel DemographicViewModel()
        {
            string[] items = new String[0];
            if (Request.Form["items"] != null) items = Request.Form["items"].Split(',');
            int pollID = int.Parse(Request.Form["pollID"]);
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<Question> questions = poll.questions;
            String hasfield = Request.Form["field"];
            if (hasfield == null) return QuestionViewModel(pollID);
            ParticipantField field = ParticipantRepository.GetParticipantFieldByID(int.Parse(Request.Form["field"]));
            bool include;
            if (Request.Form["include"].Equals("include")) include = true;
            else include = false;
            IList<ParticipantFieldValue> selected;
            IList<Participant> participants;
            if (poll.isGroup)
            {
                IList<ParticipantGroup> groupd;
                if (include) selected = field.fieldValues.Where(valu => items.Contains(valu.value)).ToList();                  
                else selected = field.fieldValues.Where(valu => !items.Contains(valu.value)).ToList();                    
                groupd = (from x in selected where x.groupd != null select x.groupd).ToList();
                participants = poll.participants.Where(p => groupd.Contains(p.group)).ToList();
            }
            else
            {
                selected = field.fieldValues.Where(valu => items.Contains(valu.value)).ToList();
                participants = (from x in selected where x.participant != null select x.participant).ToList();
                if (include==false)
                {
                    IList<Participant> included = poll.participants.SkipWhile(p=>participants.Contains(p)).ToList();
                    participants = included;
                }
            }
            IDictionary<Question, IDictionary<String, int>> questionResponses = new Dictionary<Question, IDictionary<String, int>>();

            // For each of the poll's questions
            foreach (Question question in questions)
            {
                // Create a dictionary to store that question's responses
                IDictionary<String, int> responses = new Dictionary<String, int>();

                if (question.type == QuestionType.Numeric)
                {
                    // If a numeric question
                    NumericQuestion numericQuestion = QuestionRepository.GetQuestionByID<NumericQuestion>(question.questionID);

                    int numCorrect = 0;
                    int numIncorrect = 0;

                    foreach (var response in numericQuestion.responses)
                    {
                        if (participants.Contains(response.participant))
                        {
                            // Check if the answer is correct
                            if ((Convert.ToInt32(response.response) < numericQuestion.lessThan) &&
                                (Convert.ToInt32(response.response) > numericQuestion.greaterThan))
                            {
                                numCorrect+=response.participant.votingWeight;
                            }
                            else
                            {
                                numIncorrect += response.participant.votingWeight; ;
                            }
                        }
                    }

                    responses.Add("Correct [" + numericQuestion.greaterThan.ToString() +
                            " - " + numericQuestion.lessThan.ToString() + "]", numCorrect);
                    responses.Add("Incorrect", numIncorrect);

                }
                else if (question.type == QuestionType.Alphanumeric)
                {
                    // If an alphanumeric question
                    AlphanumericQuestion alphaQuestion = QuestionRepository.GetQuestionByID<AlphanumericQuestion>(question.questionID);

                    //  Get correct responses
                    int numCorrect = 0;
                    int numIncorrect = 0;
                    int total = 0;

                    foreach (var response in alphaQuestion.responses)
                    {
                        if (participants.Contains(response.participant))
                        {
                            foreach (var answer in alphaQuestion.answers)
                            {
                                if (response.response.Equals(answer.answer))
                                {
                                    numCorrect+=response.participant.votingWeight;
                                }
                            }
                            total+=response.participant.votingWeight;
                        }
                    }

                    // Build a string of correct answers
                    String correctAnswers = "";
                    foreach (var answer in alphaQuestion.answers)
                    {
                        if (correctAnswers != "")
                        {
                            correctAnswers += ", ";
                        }
                        correctAnswers += answer.answer;
                    }

                    responses.Add("Correct [" + correctAnswers + "]", numCorrect);
                    numIncorrect = total - numCorrect;
                    responses.Add("Incorrect", numIncorrect);
                }
                else
                {
                    // IF MCQ
                    MultipleChoiceQuestion multipleQuestion = QuestionRepository.GetQuestionByID<MultipleChoiceQuestion>(question.questionID);

                    foreach (var option in multipleQuestion.options)
                    {
                        int a = (from o in option.responses where participants.Contains(o.participant) select o.participant.votingWeight*Math.Abs(o.rank)).Sum();
                        responses.Add(option.answer, a);
                    }
                }

                // Add the question and its responses to the Dictionary
                questionResponses.Add(question, responses);
            }
            return new PollReportViewModel(pollID, poll.name, questions, questionResponses, field, include, items);
        }
        [Authorize]
        [HttpPost]
        public ActionResult DemographicReportTextual()
        {
            PollReportViewModel model = DemographicViewModel();
            CodeFile1 tryomg = new CodeFile1();
            PdfPTable table = tryomg.QuestionReport(Server.MapPath("/Resources"), model, null);
            IList<IElement> stuff = new List<IElement>();
            stuff.Add(table);
            tryomg.CreatePDF(stuff, Server.MapPath("/Resources"),"Results by Question with Demographic Comparison Report",model.name);
            return View(model);
        }
        [Authorize]
        public ActionResult DemographicReportGraphical (int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            return View(QuestionViewModel(pollID));
        }
        [Authorize]
        [HttpPost]
        public ActionResult DemographicReportGraphical()
        {
            return View(DemographicViewModel());
        }

        [Authorize]
        public Boolean SetPageInstruction(int pollID, String nextWebURL, String nextScreenURL)
        {
            var poll = PollRepository.GetPollByID(pollID);
            poll.instruction.NextWebURL = nextWebURL;
            poll.instruction.NextScreenURL = nextScreenURL;

            return PollRepository.UpdatePoll(poll);
        }

        [OutputCache(Duration = 3, VaryByParam = "*")]
        public JsonResult GetPageInstruction(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            return Json(poll.instruction);
        }

        [Authorize]
        public Boolean DeletePageInstruction(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            poll.instruction = null;
            return PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public void CopyParticipantsToLinkedPoll(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var linkedPoll = poll.linkedPoll;
            if (linkedPoll.questions.Count > 0)
            {
                foreach (var participant in poll.participants)
                {
                    if (!linkedPoll.participants.Contains(participant))
                    {
                        linkedPoll.participants.Add(participant);
                    }
                }
            }
        }

        [Authorize]
        public Boolean SetPollFinished(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            poll.hasFinished = true;
            return PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public void RemoveTestParticipants(int pollID)
        {
            Poll p = PollRepository.GetPollByID(pollID);

            var testParticipants = p.participants.Where(par => par.isTestParticipant);
            var use = testParticipants.ToList();
            foreach (var participant in use)
            {
                p.gridResponses.Remove(new Keypad(participant.deviceID));
                p.participants.Remove(participant);
            }
            PollRepository.UpdatePoll(p);
            foreach (var participant in use)
            {
                ParticipantRepository.Delete(participant.participantID);
            }
        }

        [Authorize]
        public Boolean SetStartDate(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            if (poll.pollStart == null)
            {
                poll.pollStart = DateTime.Now;
            }
            return PollRepository.UpdatePoll(poll);
        }

        [Authorize]
        public ActionResult EntityHierarchy(int pollID)
        {
            var poll = PollRepository.GetPollByID(pollID);
            var user = UserRepository.GetUserByUsername(User.Identity.Name);
            Entity root = null;
            foreach (Entity e in poll.entities)
            {
                if (e.parent == null)
                {
                    root = e;
                    break;
                }
            }
            var model = new ManageEntityHierarchyViewModel(pollID, poll.name, root, poll);
            ViewData["pollRoles"] = SecurityHelper.GetRolesForPole(user, poll);
            return View(model);
        }

        [HttpPost]
        public void RenameEntity(int entityID, int pollID, string entityName)
        {
            if (entityID == -1)
            {
                var entity = new Entity(entityName);
                var poll = PollRepository.GetPollByID(pollID);
                poll.entities.Add(entity);
                PollRepository.UpdatePoll(poll);
            }
            else
            {
                var entity = EntityRepository.GetEntityByEntityID(entityID);
                entity.name = entityName;
                EntityRepository.Update(entity);
            }
        }

        [HttpPost]
        public int CreateEntity(int parentEntityID, string pollID, string entityName)
        {
            var parent = EntityRepository.GetEntityByEntityID(parentEntityID);
            var entity = new Entity(entityName, parent);
            var poll = PollRepository.GetPollByID(Int32.Parse(pollID));
            poll.entities.Add(entity);
            PollRepository.UpdatePoll(poll);
            return entity.entityID;
        }

        [HttpPost]
        public void MoveEntity(int entityID, int newParentEntityID, string pollID, string copy)
        {
            var parent = EntityRepository.GetEntityByEntityID(newParentEntityID);
            var entity = EntityRepository.GetEntityByEntityID(entityID);
            if (copy == "true")
            {
                var newEntity = new Entity(entity.name);
                newEntity.parent = parent;
                var poll = PollRepository.GetPollByID(Int32.Parse(pollID));
                poll.entities.Add(newEntity);
                PollRepository.UpdatePoll(poll);
            }
            else
            {
                entity.parent = parent;
                EntityRepository.Update(entity);
            }
        }

        [HttpPost]
        public void DeleteEntity(int entityID)
        {
            if (entityID != -1)
            {
                var entity = EntityRepository.GetEntityByEntityID(entityID);
                entity.isDeleted = true;
                IList<Entity> children = EntityRepository.GetChildren(entity);
                foreach (Entity e in children)
                {
                    DeleteEntity(e.entityID);
                }
                EntityRepository.Update(entity);
            }
        }

        public static string GetEntityTree(Entity root)
        {
            string htmlOutput = string.Empty;

            if (root != null && root.isDeleted == false)
            {
                htmlOutput += "<li id='" + root.entityID + "'><a href='#'>" + root.name + "</a>";
                IList<Entity> children = EntityRepository.GetChildren(root);
                if (children != null && children.Count > 0)
                {
                    htmlOutput += "<ul>";
                    foreach (Entity e in children)
                    {
                        htmlOutput += GetEntityTree(e);
                    }
                    htmlOutput += "</ul>";
                }
                htmlOutput += "</li>";
            }

            return htmlOutput;
        }
    }
}
